home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / prg_gen / euphor14.zip / TTT.EX < prev    next >
Text File  |  1995-04-28  |  19KB  |  896 lines

  1.         -------------------------------
  2.         -- 3-Dimensional Tic Tac Toe --
  3.         -------------------------------
  4.  
  5. -- Play 3 dimensional tic-tac-toe against one of two computer algorithms
  6. -- or against another human -- or let the two computer algorithms play
  7. -- each other. Which algorithm is better?
  8.  
  9. -- There are two major data structures. positions describes each board 
  10. -- position. lines describes each possible winning line of 4 positions  
  11. -- in a row.
  12.  
  13. include graphics.e
  14. include mouse.e
  15.  
  16. constant TRUE = 1, FALSE = 0
  17. constant ON = 1, OFF = 0
  18.  
  19. constant COLORS = {BRIGHT_RED, BRIGHT_GREEN, YELLOW, BRIGHT_MAGENTA}
  20.  
  21. sequence pcolors -- colors of circular markers
  22. pcolors = {BRIGHT_BLUE, BRIGHT_WHITE}
  23.  
  24. constant SQUARE_SIZE = 24
  25.  
  26. constant TOP_LEFT = {240, 26}
  27.  
  28. constant KEYB = 0, SCREEN = 1  -- I/O devices
  29.  
  30. constant
  31.     NPOSITIONS = 64,  -- number of board positions
  32.     NLINES = 76   -- number of 4-in-a-row lines
  33.  
  34. type line(integer x)
  35.     return x >= 0 and x <= NLINES
  36. end type
  37.  
  38. type Position(integer x)
  39.     return x >= 0 or x <= NPOSITIONS
  40. end type
  41.  
  42. type all_positions(sequence x)
  43.     return length(x) = NPOSITIONS
  44. end type
  45.  
  46. type all_lines(sequence x)
  47.     return length(x) = NLINES
  48. end type
  49.  
  50. type boolean(integer x)
  51.     return x = TRUE or x = FALSE
  52. end type
  53.  
  54. type players(sequence x)
  55.     return length(x) = 4
  56. end type
  57.  
  58. type player_number(integer x)
  59.     return x = 1 or x = 2
  60. end type
  61.  
  62. type positive_int(integer x)
  63.     return x >= 1
  64. end type
  65.  
  66. type natural(integer x)
  67.     return x >= 0
  68. end type
  69.  
  70. type human_count(integer x)
  71.     return x >=0 and x <= 2
  72. end type
  73.  
  74. type move_value(integer x)
  75.     return integer(x) and x >= -1
  76. end type
  77.  
  78. type time_delay(integer x)
  79.     return x >= 0 and x < 1000
  80. end type
  81.  
  82. type reason_number(integer x)
  83.     return x >= 1 and x <= 10
  84. end type
  85.  
  86. type three_digits(sequence x)
  87.     return length(x) = 3
  88. end type
  89.  
  90. type move_number(integer x)
  91.     return x >= 111 and x <= 444
  92. end type
  93.  
  94. all_positions positions
  95.     -- positions is a list of all the board positions
  96.  
  97. constant
  98.     -- positions 2-d sequence columns:
  99.     LINES_THRU = 1, -- the number of lines passing through this position
  100.     LINE1 = 2,      -- the first of up to 7 lines passing
  101.             -- through this position
  102.     NLIVE = 9,      -- the number of "live" lines passing through this position
  103.     NEXTP = 10,     -- index of next position (or 0)
  104.     PREVP = 11,     -- index of previous position (or 0)
  105.     AVAIL = 12      -- is this position available, 1 = yes, 0 = no
  106.  
  107. all_lines lines     -- lines is a list of all the lines of 4 positions in a row
  108.             -- it is indexed from 1 to NLINES
  109.  
  110. constant
  111.     -- lines 2-d sequence columns:
  112.     COUNT = 1,   -- number of "live" markers on this line
  113.     POS1 = 2,    -- first position of 4
  114.     POS4 = 5,    -- last position
  115.     NEXTL = 6,   -- index of next line (or 0)
  116.     PREVL = 7,   -- index of previous line (or 0)
  117.     STATUS = 8,  -- status of this line
  118.     -- possible status of a line:
  119.     EMPTY = 0,
  120.     COMPUTER = 1,
  121.     HUMAN = 2,
  122.     DEAD = 3
  123.  
  124. sequence lp       -- L->P format
  125. all_positions pl  -- P->L format
  126. sequence dbl      -- used in 3x3 check
  127. players ptype,    -- player types
  128.     pname     -- player names
  129.  
  130. line fptr,  -- free position list
  131.      cptr,  -- computer's line list
  132.      hptr,  -- human's line list
  133.      eptr   -- empty line list
  134. player_number player
  135. natural cmoves, hmoves, l2
  136. boolean endgame, found
  137. human_count humans
  138. move_value bestval
  139. atom x
  140.  
  141. procedure Delay(time_delay t)
  142. -- waste some time
  143.     atom t0
  144.  
  145.     if humans = 0 and endgame = FALSE then
  146.     return
  147.     end if
  148.     t0 = time()
  149.     while time() < t0 + t/700 do
  150.     end while
  151. end procedure
  152.  
  153. procedure Why(reason_number reason)
  154. -- show the reason why the computer made its move
  155.     position(22, 11)
  156.     if reason = 1 then
  157.     puts(SCREEN, "BLOCK 3 IN A ROW")
  158.     elsif reason = 2 then
  159.     puts(SCREEN, "FORCE 3X3       ")
  160.     elsif reason = 3 then
  161.     puts(SCREEN, "FORCE 3-2-2-1   ")
  162.     elsif reason = 4 then
  163.     puts(SCREEN, "FORCE 3-2-2     ")
  164.     elsif reason = 5 then
  165.     puts(SCREEN, "PREVENT 3X3     ")
  166.     elsif reason = 6 then
  167.     puts(SCREEN, "PREVENT 3-2-2-1 ")
  168.     elsif reason = 7 then
  169.     puts(SCREEN, "PREVENT 3-2-2   ")
  170.     elsif reason = 8 then
  171.     printf(SCREEN, "VALUE=%d         ", bestval)
  172.     else
  173.     puts(SCREEN, "                ")
  174.     end if
  175. end procedure
  176.  
  177.  
  178. function Get4th()
  179. -- grab the final winning 4th position in a line
  180. integer pos
  181.     for z = POS1 to POS4 do
  182.     pos = lines[x][z]
  183.     if positions[lp[pos]][AVAIL] = 0 then
  184.         return pos
  185.     end if
  186.     end for
  187. end function
  188.  
  189.  
  190. function Find2()
  191. -- Find two lines that intersect where I have 2 markers on each line.
  192. -- I can take the intersection and create two lines of 3 at once.
  193. integer pos
  194.     for z = POS1 to POS4 do
  195.     pos = lines[x][z]
  196.     if positions[lp[pos]][AVAIL] = 0 then
  197.         dbl[l2] = pos
  198.         l2 = l2 + 1
  199.     end if
  200.     end for
  201.     if l2 < 4 then
  202.     return 0
  203.     end if
  204.     for z = l2 - 2 to l2 - 1 do
  205.     for z1 = 1 to l2 - 3 do
  206.         if dbl[z] = dbl[z1] then
  207.         found = TRUE
  208.         return dbl[z]
  209.         end if
  210.     end for
  211.     end for
  212.     return 0
  213. end function
  214.  
  215.  
  216. function FindA()
  217. -- find forcing pattern "A"
  218. integer k, z1, line, zz
  219.     k = 0
  220.     for z = POS1 to POS4 do
  221.     z1 = lp[lines[x][z]]
  222.     for i = LINE1 to positions[z1][LINES_THRU] + 1 do
  223.         line = positions[z1][i]
  224.         if lines[line][STATUS] = l2 then
  225.         if lines[line][COUNT] = 2 then
  226.             k = k + 1
  227.             exit
  228.         end if
  229.         end if
  230.     end for
  231.     if k = 3 then
  232.         zz = z
  233.         exit
  234.     end if
  235.     end for
  236.     if k = 3 then
  237.     found = TRUE
  238.     return lines[x][zz]
  239.     end if
  240.     return 0
  241. end function
  242.  
  243.  
  244. function FindB()
  245. -- find forcing pattern "B"
  246. integer k, z1, line
  247.     k = 0
  248.     for z = POS1 to POS4 do
  249.     z1 = lp[lines[x][z]]
  250.     if positions[z1][AVAIL] = 0 then
  251.         for i = LINE1 to positions[z1][LINES_THRU] + 1 do
  252.         line = positions[z1][i]
  253.         if lines[line][STATUS] = l2 then
  254.             if lines[line][COUNT] = 2 then
  255.             k = k + 1
  256.             exit
  257.             end if
  258.         end if
  259.         end for
  260.         if k = 2 then
  261.         found = TRUE
  262.         return lines[x][z]
  263.         end if
  264.     end if
  265.     end for
  266.     return 0
  267. end function
  268.  
  269.  
  270. function FindMax()
  271. -- find best free position
  272. integer i, bestm
  273.     i = fptr
  274.     bestval = -1
  275.     while i do
  276.     if positions[i][NLIVE] > bestval then
  277.         bestval = positions[i][NLIVE]
  278.         bestm = i
  279.     elsif positions[i][NLIVE] = bestval then
  280.         if rand(7) = 1 then
  281.         bestm = i
  282.         end if
  283.     end if
  284.     i = positions[i][NEXTP]
  285.     end while
  286.     return pl[bestm]
  287. end function
  288.  
  289. function mouse_square(sequence spot)
  290. -- map x,y mouse coordinate to plane, row, column
  291.     integer x, y
  292.     natural m
  293.  
  294.     spot = spot - TOP_LEFT
  295.     x = spot[1]
  296.     y = spot[2]
  297.     -- which plane are we on?
  298.     m = 111
  299.     while y > 4 * SQUARE_SIZE do
  300.     y = y - 4.5 * SQUARE_SIZE
  301.     x = x - 2.5 * SQUARE_SIZE
  302.     m = m + 100
  303.     end while
  304.     -- which row are we on?
  305.     while y > SQUARE_SIZE do
  306.     y = y - SQUARE_SIZE
  307.     m = m + 10
  308.     end while
  309.     if x > 4 * SQUARE_SIZE then
  310.     return 0 
  311.     end if
  312.     -- which column are we on?
  313.     while x > SQUARE_SIZE do
  314.     x = x - SQUARE_SIZE
  315.     m = m + 1
  316.     end while
  317.     if x < 0 or y < 0 then
  318.     return 0
  319.     else
  320.     return m
  321.     end if
  322. end function
  323.  
  324.  
  325. function GetMove()
  326. -- get human's move via the mouse
  327.     natural m
  328.     object event
  329.  
  330.     while TRUE do
  331.     position(20, 1)
  332.     puts(SCREEN, repeat(' ', 30))
  333.     position(20, 1)
  334.     puts(SCREEN, ' ' & pname[player])
  335.     puts(SCREEN, "'s move? ")
  336.     event = -1
  337.     while atom(event) do
  338.         event = get_mouse()
  339.         if get_key() != -1 then
  340.         if graphics_mode(-1) then
  341.         end if
  342.         abort(1)
  343.         end if
  344.     end while
  345.     m = mouse_square(event[2..3])
  346.     if m >= 111 and m <= 444 then
  347.         if lp[m] then
  348.         if positions[lp[m]][AVAIL] = 0 then
  349.             puts(SCREEN, repeat(' ', 30))
  350.             exit
  351.         end if
  352.         end if
  353.     end if
  354.     end while
  355.     return m
  356. end function
  357.  
  358.  
  359. procedure AdjValues(integer x, integer delta)
  360. -- adjust the "value" of positions along a line
  361. integer pos
  362.     for z = POS1 to POS4 do
  363.     pos = lp[lines[x][z]]
  364.     positions[pos][NLIVE] = positions[pos][NLIVE] + delta
  365.     end for
  366. end procedure
  367.  
  368.  
  369. procedure Relink(integer player, integer x)
  370. -- adjust some data structures after a move
  371.     line prev, next
  372.  
  373.     next = lines[x][NEXTL]
  374.     prev = lines[x][PREVL]
  375.  
  376.     if player = COMPUTER then
  377.     AdjValues(x, 1)
  378.     lines[x][NEXTL] = cptr
  379.     lines[x][PREVL] = 0
  380.     if cptr then
  381.         lines[cptr][PREVL] = x
  382.     end if
  383.     cptr = x
  384.     else
  385.     lines[x][NEXTL] = hptr
  386.     lines[x][PREVL] = 0
  387.     if hptr then
  388.         lines[hptr][PREVL] = x
  389.     end if
  390.     hptr = x
  391.     end if
  392.     if prev then
  393.     lines[prev][NEXTL] = next
  394.     if next then
  395.         lines[next][PREVL] = prev
  396.     end if
  397.     else
  398.     eptr = next
  399.     if eptr then
  400.         lines[eptr][PREVL] = 0
  401.     end if
  402.     end if
  403. end procedure
  404.  
  405. function digits(natural x)
  406. -- return the 3-digits in number x
  407.     three_digits d
  408.  
  409.     d = {0, 0, 0}
  410.     while x >= 100 do
  411.     d[1] = d[1] + 1
  412.     x = x - 100
  413.     end while
  414.  
  415.     while x >= 10 do
  416.     d[2] = d[2] + 1
  417.     x = x - 10
  418.     end while
  419.  
  420.     d[3] = x
  421.     return d
  422. end function
  423.  
  424.  
  425. procedure PrintMove(move_number move)
  426. -- print the move that was just made
  427.     three_digits d
  428.     integer px, py
  429.  
  430.     d = digits(move)
  431.     py = (d[1] - 1) * 4.5 * SQUARE_SIZE + (d[2]-1) * SQUARE_SIZE + TOP_LEFT[2]
  432.     px = (d[1] - 1) * 2.5 * SQUARE_SIZE + (d[3]-1) * SQUARE_SIZE + TOP_LEFT[1]
  433.     mouse_pointer(OFF)
  434.     for i = 1 to 3 do
  435.     ellipse(GRAY, 1, {px+1, py+1}, 
  436.               {px + SQUARE_SIZE - 2, py + SQUARE_SIZE - 2})
  437.     Delay(70)
  438.     ellipse(pcolors[player], 1, {px+1, py+1}, 
  439.                     {px + SQUARE_SIZE - 2, py + SQUARE_SIZE - 2})
  440.     Delay(70)
  441.     end for
  442.     mouse_pointer(ON)
  443.     if endgame then
  444.     return
  445.     end if
  446.     if player = COMPUTER then
  447.     cmoves = cmoves + 1
  448.     else
  449.     hmoves = hmoves + 1
  450.     end if
  451. end procedure
  452.  
  453.  
  454. procedure Another(line x)
  455. -- add to the number of positions occupied by a player
  456. -- along a line x
  457.     integer inarow
  458.  
  459.     inarow = lines[x][COUNT] + 1
  460.     lines[x][COUNT] = inarow
  461.     if inarow < 4 then
  462.     return
  463.     end if
  464.     position(21,6)
  465.     text_color(BRIGHT_RED)
  466.     puts(SCREEN, pname[player])
  467.     puts(SCREEN, " WINS!          ")
  468.     text_color(YELLOW)
  469.     endgame = TRUE
  470.     mouse_pointer(OFF)
  471.     for i = 1 to 4 do
  472.     for j = POS1 to POS4 do
  473.         PrintMove(lines[x][j])
  474.     end for
  475.     Delay(80)
  476.     end for
  477.     mouse_pointer(ON)
  478. end procedure
  479.  
  480.  
  481. procedure Delete_c(line x)
  482. -- delete from computer list
  483.     line prev, next
  484.  
  485.     prev = lines[x][PREVL]
  486.     next = lines[x][NEXTL]
  487.     if prev then
  488.     lines[prev][NEXTL] = next
  489.     else
  490.     cptr = next
  491.     end if
  492.     if next then
  493.     lines[next][PREVL] = prev
  494.     end if
  495. end procedure
  496.  
  497.  
  498. procedure Delete_h(line x)
  499. -- delete from human list
  500.     line prev, next
  501.  
  502.     prev = lines[x][PREVL]
  503.     next = lines[x][NEXTL]
  504.     if prev then
  505.     lines[prev][NEXTL] = next
  506.     else
  507.     hptr = next
  508.     end if
  509.     if next then
  510.     lines[next][PREVL] = prev
  511.     end if
  512. end procedure
  513.  
  514.  
  515. procedure init()
  516. -- initialize variables
  517.     integer temp, u, line, t
  518.  
  519.     clear_screen()
  520.     endgame = FALSE
  521.     cmoves = 0
  522.     hmoves = 0
  523.     for i = 1 to NLINES do
  524.     lines[i][STATUS] = EMPTY
  525.     lines[i][COUNT] = 0
  526.     end for
  527.     for i = 1 to NPOSITIONS do
  528.     positions[i][LINES_THRU] = 0
  529.     positions[i][AVAIL] = 0
  530.     end for
  531.     line = 1
  532.     for i = POS1 to POS4 do
  533.     lines[line][i] = (i-1) * 111
  534.     lines[line+1][i] = (i-1) * 109 + 5
  535.     lines[line+2][i] = (i-1) * 91 + 50
  536.     lines[line+3][i] = (i-1) * 89 + 55
  537.     end for
  538.     line = line + 4
  539.     for i = 1 to 4 do
  540.     for j = POS1 to POS4 do
  541.         lines[line][j] = i * 100 + (j-1) * 11
  542.         lines[line+1][j] = i * 100 + (j-1) * 9 + 5
  543.         lines[line+2][j] = (j-1) * 101 + i * 10
  544.         lines[line+3][j] = (j-1) * 99 + i * 10 + 5
  545.         lines[line+4][j] = (j-1) * 110 + i
  546.         lines[line+5][j] = (j-1) * 90 + 50 + i
  547.     end for
  548.     line = line + 6
  549.     end for
  550.     for i = 1 to 4 do
  551.     for j = 1 to 4 do
  552.         for k = POS1 to POS4 do
  553.         t = 100 * i + 10 * j + k - 1
  554.         u = (i - 1) * 16 + (j - 1) * 4 + k - 1
  555.         lp[t] = u
  556.         pl[u] = t
  557.         lines[line][k] = t
  558.         lines[line+1][k] = 100 * j + 10 * (k-1) + i
  559.         lines[line+2][k] = 100 * (k-1) + 10 * i + j
  560.         end for
  561.         line = line + 3
  562.     end for
  563.     end for
  564.     for i = 1 to NPOSITIONS do
  565.     positions[i][PREVP] = i - 1
  566.     positions[i][NEXTP] = i + 1
  567.     end for
  568.     positions[1][PREVP] = 0
  569.     positions[NPOSITIONS][NEXTP] = 0
  570.     fptr = 1
  571.     for i = 1 to NLINES do
  572.     lines[i][NEXTL] = i + 1
  573.     lines[i][PREVL] = i - 1
  574.     for j = POS1 to POS4 do
  575.         t = lines[i][j]
  576.         u = lp[t]
  577.         temp = positions[u][LINES_THRU] + 1
  578.         positions[u][LINES_THRU] = temp
  579.         positions[u][temp+1] = i
  580.     end for
  581.     end for
  582.     cptr = 0
  583.     hptr = 0
  584.     eptr = 0
  585.     lines[NLINES][NEXTL] = 0
  586.     lines[1][PREVL] = 0
  587.     for i = 1 to NPOSITIONS do
  588.     positions[i][NLIVE] = positions[i][LINES_THRU]
  589.     end for
  590.     position(15, 2)
  591.     text_color(COLORS[1])
  592.     puts(SCREEN, "3-D ")
  593.     text_color(COLORS[2])
  594.     puts(SCREEN, "tic ")
  595.     text_color(COLORS[3])
  596.     puts(SCREEN, "TAC ")
  597.     text_color(COLORS[4])
  598.     puts(SCREEN, "toe ")
  599. end procedure
  600.  
  601.  
  602. procedure UpdateMove(move_number m)
  603. -- update data structures after making move m
  604.     Position x1
  605.     line x2
  606.     integer prev, next, val, s
  607.  
  608.     x1 = lp[m]
  609.     positions[x1][AVAIL] = 1
  610.     prev = positions[x1][PREVP]
  611.     next = positions[x1][NEXTP]
  612.     if prev then
  613.     positions[prev][NEXTP] = next
  614.     if next then
  615.         positions[next][PREVP] = prev
  616.     end if
  617.     else
  618.     fptr = next
  619.     if fptr then
  620.         positions[fptr][PREVP] = 0
  621.     end if
  622.     end if
  623.     for j = LINE1 to 1+positions[x1][LINES_THRU] do
  624.     x2 = positions[x1][j]
  625.     s = lines[x2][STATUS]
  626.     if s = EMPTY then
  627.         lines[x2][STATUS] = player
  628.         lines[x2][COUNT] = 1
  629.         Relink(player, x2)
  630.     elsif s = COMPUTER then
  631.         if player = COMPUTER then
  632.         Another(x2)
  633.         else
  634.         lines[x2][STATUS] = DEAD
  635.         AdjValues(x2, -2)
  636.         Delete_c(x2)
  637.         end if
  638.     elsif s = HUMAN then
  639.         if player = HUMAN then
  640.         Another(x2)
  641.         if lines[x2][COUNT] = 2 then
  642.             val = 4
  643.         else
  644.             val = 0
  645.         end if
  646.         AdjValues(x2, val)
  647.         else
  648.         if lines[x2][COUNT] > 1 then
  649.             val = -5
  650.         else
  651.             val = -1
  652.         end if
  653.         lines[x2][STATUS] = DEAD
  654.         AdjValues(x2, val)
  655.         Delete_h(x2)
  656.         end if
  657.     end if
  658.     end for
  659. end procedure
  660.  
  661.  
  662. function Think()
  663. -- pick the best move, return {move, reason for it}
  664.     integer m, mymoves, myptr, me, him, hisptr, hismoves
  665.  
  666.     found = FALSE
  667.     if player = COMPUTER then
  668.     mymoves = cmoves
  669.     hismoves = hmoves
  670.     myptr = cptr
  671.     hisptr = hptr
  672.     me = COMPUTER
  673.     him = HUMAN
  674.     else
  675.     mymoves = hmoves
  676.     hismoves = cmoves
  677.     myptr = hptr
  678.     hisptr = cptr
  679.     me = HUMAN
  680.     him = COMPUTER
  681.     end if
  682.  
  683.     -- Have I got 3 in a row?
  684.     if mymoves >= 3 then
  685.     x = myptr
  686.     while x do
  687.         if lines[x][COUNT] = 3 then
  688.         return {Get4th(), 9}
  689.         end if
  690.         x = lines[x][NEXTL]
  691.     end while
  692.     end if
  693.  
  694.     -- Does the other guy have 3 in a row?
  695.     if hismoves >= 3 then
  696.     x = hisptr
  697.     while x do
  698.         if lines[x][COUNT] = 3 then
  699.         return {Get4th(), 1}
  700.         end if
  701.         x = lines[x][NEXTL]
  702.     end while
  703.     end if
  704.  
  705.     -- Do I have a 2x2 force?
  706.     if mymoves >= 4 then
  707.     x = myptr
  708.     l2 = 1
  709.     while x do
  710.         if lines[x][COUNT] = 2 then
  711.         m = Find2()
  712.         if found then
  713.             return {m, 2}
  714.         end if
  715.         end if
  716.         x = lines[x][NEXTL]
  717.     end while
  718.  
  719.     -- Do I have a 3-2-2-1 force ?
  720.     x = eptr
  721.     l2 = me
  722.     while x do
  723.         m = FindA()
  724.         if found then
  725.         return {m, 3}
  726.         end if
  727.         x = lines[x][NEXTL]
  728.     end while
  729.  
  730.     -- do I have a 3-2-2 force?
  731.     if mymoves >= 5 then
  732.         x = myptr
  733.         while x do
  734.         if lines[x][COUNT] = 1 then
  735.             m = FindB()
  736.             if found then
  737.             return {m, 4}
  738.             end if
  739.         end if
  740.         x = lines[x][NEXTL]
  741.         end while
  742.     end if
  743.     end if
  744.  
  745.     -- does the other guy have a 2x2 force?
  746.     if hismoves >= 4 then
  747.     x = hisptr
  748.     l2 = 1
  749.     while x do
  750.         if lines[x][COUNT] = 2 then
  751.         m = Find2()
  752.         if found then
  753.             return {m, 5}
  754.         end if
  755.         end if
  756.         x = lines[x][NEXTL]
  757.     end while
  758.  
  759.     -- does the other guy have a 3-2-2-1 force?
  760.     x = eptr
  761.     l2 = him
  762.     while x do
  763.         m = FindA()
  764.         if found then
  765.         return {m, 6}
  766.         end if
  767.         x = lines[x][NEXTL]
  768.     end while
  769.  
  770.     -- does the other guy have a 3-2-2 force?
  771.     if hismoves >= 5 then
  772.         x = hisptr
  773.         while x do
  774.         if lines[x][COUNT] = 1 then
  775.             m = FindB()
  776.             if found then
  777.             return {m, 7}
  778.             end if
  779.         end if
  780.         x = lines[x][NEXTL]
  781.         end while
  782.     end if
  783.     end if
  784.     -- just pick the move with the most possibilities
  785.     return {FindMax(), 8}
  786. end function
  787.  
  788.  
  789. procedure Setup()
  790. -- create major sequences
  791.     object name
  792.  
  793.     positions = repeat(repeat(0, 12), NPOSITIONS)
  794.     lines = repeat(repeat(0, 8), NLINES)
  795.     lp = repeat(0, 444)
  796.     pl = repeat(0, 64)
  797.     dbl = repeat(0, 52)
  798.     ptype = repeat(0, 4)
  799.     pname = ptype
  800.     ptype[1] = COMPUTER
  801.     ptype[2] = COMPUTER
  802.     pname[1] = "DEFENDO"
  803.     pname[2] = "AGGRESSO"
  804.     position(15, 1)
  805.     puts(SCREEN, " Name of player 1? (cr for DEFENDO) ")
  806.     name = gets(KEYB)
  807.     name = name[1..length(name)-1]
  808.     humans = 0
  809.     if length(name) > 0 then
  810.     pname[1] = name
  811.     ptype[1] = HUMAN
  812.     humans = humans + 1
  813.     end if
  814.     puts(SCREEN, "\n Name of player 2? (cr for AGGRESSO) ")
  815.     name = gets(KEYB)
  816.     name = name[1..length(name)-1]
  817.     if (length(name) > 0) then
  818.     pname[2] = name
  819.     ptype[2] = HUMAN
  820.     humans = humans + 1
  821.     end if
  822. end procedure
  823.  
  824. procedure draw_plane(integer color, integer x, integer y)
  825. -- draw one plane of the board
  826.      for i = 0 to 4 do
  827.     draw_line(color, {{x, y+i*SQUARE_SIZE}, 
  828.               {x+4*SQUARE_SIZE, y+i*SQUARE_SIZE}})
  829.      end for
  830.      for i = 0 to 4 do
  831.     draw_line(color, {{x+i*SQUARE_SIZE, y},
  832.               {x+i*SQUARE_SIZE, y+4*SQUARE_SIZE}})
  833.      end for
  834. end procedure
  835.  
  836. procedure make_board(sequence top_left)
  837. -- display the board
  838.     bk_color(8)
  839.     for i = 0 to 3 do
  840.     draw_plane(COLORS[i+1], top_left[1]+2.5*SQUARE_SIZE*i, 
  841.                 top_left[2]+4.5*SQUARE_SIZE*i)
  842.     end for
  843. end procedure
  844.  
  845. procedure ttt()
  846. -- this is the main routine
  847.     sequence m
  848.  
  849.     Setup()
  850.     player = rand(2) -- first game is random 
  851.              -- loser goes first in subsequent games
  852.     while TRUE do
  853.     mouse_pointer(OFF)
  854.     init()
  855.     make_board(TOP_LEFT)
  856.     mouse_pointer(ON)
  857.     text_color(YELLOW)
  858.     mouse_events(LEFT_DOWN)
  859.     while endgame = FALSE do
  860.         if fptr then
  861.         if ptype[player] = HUMAN then
  862.             m = {GetMove()}
  863.         else
  864.             m = Think()
  865.             Why(m[2])
  866.         end if
  867.         PrintMove(m[1])
  868.         UpdateMove(m[1])
  869.         player = 3 - player
  870.         else
  871.         position(18,1)
  872.         puts(SCREEN, " A DRAW             ")
  873.         Delay(500)
  874.         exit
  875.         end if
  876.     end while
  877.     position(19, 1)
  878.     text_color(BRIGHT_MAGENTA)
  879.     puts(SCREEN, " Another game? (y or n) ")
  880.     text_color(YELLOW)
  881.     if find('n', gets(KEYB)) then
  882.         exit
  883.     end if
  884.     end while
  885. end procedure
  886.  
  887. if graphics_mode(18) then -- VGA
  888.     puts(1, "VGA graphics is required\n")
  889. else
  890.     ttt()
  891. end if
  892.  
  893. if graphics_mode(-1) then
  894. end if
  895.  
  896.